﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Text;
using System.Threading;

namespace WebParser
{
    [Obsolete("", true)]
    public class MultipartReceiver
    {
        public event EventHandler<ContentEventArgs> ContentReceived;
        public event EventHandler<ErrorEventArgs> Error;
        protected virtual void OnError(ErrorEventArgs e)
        {
            if (Error != null) Error(this, e);
        }

        private string _url;
        private string _method;
        private string _boundary;
        private readonly Encoding _enc = Encoding.ASCII;
        private readonly List<byte> _tmp = new List<byte>();
        private string _contentType;
        private int _contentLength;
        private Action<byte> _p;
        private readonly List<object> _sync = new List<object>();
        private bool GetSync(object token)
        {
            return _sync.Contains(token);
        }
        private void SetSync(object token, bool enable)
        {
            var contains = _sync.Contains(token);
            if ((enable && contains) || (!enable && !contains)) return;
            if (enable)
                _sync.Add(token);
            else
                _sync.Remove(token);
        }
        public bool IsRunning
        {
            get { return GetSync("IsRunning"); }
            private set { SetSync("IsRunning", value); }
        }
        protected bool KeepRunning
        {
            get { return GetSync("KeepRunning"); }
            set { SetSync("KeepRunning", value); }
        }

        private void SwitchTo(Action<byte> function)
        {
            var source = (_p == null) ? "{EMPTY}" : _p.Method.Name;
            var target = (function == null) ? "{EMPTY}" : function.Method.Name;
            Debug.WriteLine(string.Format("{0} => {1}", source, target));
            _p = function;
        }
        public bool Start(string url, string method)
        {
            if (IsRunning) return false;
            IsRunning = true;
            KeepRunning = true;
            _url = url;
            _method = method;
            new Thread(Connect) { IsBackground = true }.Start();
            return true;
        }
        private void ReadBoundary(byte b)
        {
            if (b == '\r') return;
            if (b == '\n')
            {
                var line = _enc.GetString(_tmp.ToArray());
                if (line == _boundary)
                    SwitchTo(ReadFrameHeader);
                _tmp.Clear();
                return;
            }
            _tmp.Add(b);
        }
        private void ReadFrameHeader(byte b)
        {

            if (b == '\r') return;
            if (b == '\n')
            {
                if (_tmp.Count < 1)
                {
                    SwitchTo(ReadFrameData);
                    return;
                }
                var line = _enc.GetString(_tmp.ToArray());
                var index = line.IndexOf(": ");
                if (index > -1)
                {
                    var key = line.Substring(0, index);
                    switch (key)
                    {
                        case "Content-Type":
                            _contentType = line.Substring(index + 2);
                            break;
                        case "Content-Length":
                            int len;
                            if (int.TryParse(line.Substring(index + 2), out len))
                                _contentLength = len;
                            break;
                    }
                }
                _tmp.Clear();
                return;
            }
            _tmp.Add(b);
        }

        private void ReadFrameData(byte b)
        {
            _tmp.Add(b);
            if (_tmp.Count < _contentLength) return;
            if (ContentReceived != null)
            {
                var e = new ContentEventArgs(_tmp.ToArray(), _contentType, _contentLength);
                ContentReceived(this, e);
                _contentType = null;
                _contentLength = -1;
            }
            _tmp.Clear();
            SwitchTo(ReadBoundary);
        }

        private void Connect()
        {
            var buffer = new byte[0x2000];
            var r = SendUrlCommand(_url, _method);
            var index = r.ContentType.IndexOf("boundary=");
            if (index < 0)
            {
                IsRunning = false;
                return;
            }
            _boundary = "--" + r.ContentType.Substring(index + 9);
            SwitchTo(ReadBoundary);
            using (var s = r.GetResponseStream())
            {
                if (s == null)
                {
                    IsRunning = false;
                    return;
                }
                while (KeepRunning)
                {
                    var len = s.Read(buffer, 0, buffer.Length);
                    for (var i = 0; i < len; i++)
                        _p(buffer[i]);
                }
            }
            IsRunning = false;
        }

        public void Stop()
        {
            KeepRunning = false;
        }
        private static WebResponse SendUrlCommand(string urlCommand, string method)
        {
            var request = WebRequest.Create(urlCommand);
            request.Proxy = null;
            request.Method = method;
            return request.GetResponse();
        }
    }
}